#include <stdio.h>
#include <SDL/SDL.h>
#include <SDL/SDL_ttf.h>

#include <vector>
#include <malloc.h>

#include <sys/types.h>
#include <sys/stat.h>

#include "Fenetre/FenetreJeu.h"
#include "Fenetre/FenMenu.h"
#include "Fenetre/FenOption.h"
#include "Fenetre/FenScores.h"
#include "Fenetre/FenJeuResaux.h"
#include "Score.h"

#include "gestionTouche.h"

#include "ListeChainee.h"
#include "Iterator.h"

//g++ `sdl-config --cflags --libs` -lSDL_image -lSDL_ttf -lSDL_gfx -std=c++0x


bool estVide(const char *chaine)
{
    for(; (*chaine) != '\0' ; chaine++)
        if((*chaine) != ' ')
            return false;
    return true;
}

vector<Score_struct> listeScore(const char *nom)
{
    vector<Score_struct> vector;

    FILE *f = fopen(nom,"rb");
    if(f!=NULL && !feof(f))
    {
        for(int i = 0 ; !feof(f) ; i++)
        {
            Score_struct s = Score::lireScore(f);
            if(!estVide(s.nom.c_str()))
            {
                vector.push_back(s);
            }
        }
        fclose(f);
    }
    return vector;
}


int compareToScore_struct(void * v1 , void * v2)
{
    Score_struct*  s1 = (Score_struct*)v1;
    Score_struct*  s2 = (Score_struct*)v2;

    return s1->val - s2->val;
}

int compareToScore_structMoy(void * v1 , void * v2)
{
    Score_struct_Moyenne*  s1 = (Score_struct_Moyenne*)v1;
    Score_struct_Moyenne*  s2 = (Score_struct_Moyenne*)v2;

    return s2->valMax - s1->valMax;
}

ListeChainee* listeScoreChaine(const char *nom)
{
    ListeChainee * vector = new ListeChainee(compareToScore_struct);

    FILE *f = fopen(nom,"r");

    if(f!=NULL && !feof(f))
    {
        for(int i = 0 ; !feof(f) ; i++)
        {
            Score_struct s = Score::lireScore(f);
            Score_struct *ps = new Score_struct ;
            ps->nom = s.nom;
            ps->val = s.val;
            if(!estVide(s.nom.c_str()))
            {
                vector->add((void*)ps);
            }
        }
        fclose(f);
    }

    return vector;
}

Score_struct_Moyenne lireScoreMoyenne(FILE *f )
{
    Score_struct_Moyenne s;
    s.nbPartie = s.valMax = s.valMin = s.valMoy = -1;
    s.nom = "";

    int tailleNom;
    int valMin ;
    int valMax;
    int valMoy;
    int nbPartie;

    if(fread(&tailleNom,sizeof(int) , 1 , f) <= 0)
        return s;

    char nom[100];
    nom[99] = '\0';

    if(tailleNom >= 100 || tailleNom <= 0 || fread(nom,sizeof(char) , tailleNom , f) <= 0)
        return s;
    nom[tailleNom] = '\0';

    int tailleLu = 0;
    if((tailleLu = fread(&nbPartie,sizeof(int) , 1 , f)) <= 0){
        perror("lecture : ");
        return s;
    }

    if(fread(&valMax,sizeof(int) , 1 , f) <= 0)
        return s;

   if(fread(&valMin,sizeof(int) , 1 , f) <= 0)
        return s;

   if(fread(&valMoy,sizeof(int) , 1 , f) <= 0)
        return s;

    s.nom = nom;
    s.valMax = valMax;
    s.valMin = valMin;
    s.valMoy = valMoy;
    s.nbPartie = nbPartie;

    return s;
}


void saveScoreMoyenne(Score_struct_Moyenne scoreAct , FILE *f)
{
    char *nom = (char*)scoreAct.nom.c_str();
    int tailleNom = scoreAct.nom.size();
    fwrite(&tailleNom , sizeof(int) , 1 , f);
    fwrite(nom , sizeof(char) , tailleNom , f);
    fwrite(&(scoreAct.nbPartie) , sizeof(int) , 1 , f);
    fwrite(&(scoreAct.valMax) , sizeof(int) , 1 , f);
    fwrite(&(scoreAct.valMin) , sizeof(int) , 1 , f);
    fwrite(&(scoreAct.valMoy) , sizeof(int) , 1 , f);
}

ListeChainee* listeScoreMoyenneChaine(const char *nom)
{
    ListeChainee * vector = new ListeChainee(compareToScore_structMoy);

    FILE *f = fopen(nom,"r");

    if(f!=NULL && !feof(f))
    {
        for(int i = 0 ; !feof(f) ; i++)
        {
            Score_struct_Moyenne s = lireScoreMoyenne(f);
            Score_struct_Moyenne *ps = new Score_struct_Moyenne ;
            (*ps) = s;
            if(!estVide(s.nom.c_str()))
            {
                vector->add((void*)ps);
            }
        }
        fclose(f);
    }
    else
    {
        cout << "le fichier : " << nom << " n'existe pas " << endl;
    }

    return vector;
}

/*** crer les fichier de configuration si ils n'existe pas ***/
void crerConfigFile()
{
    char *nomUser = getenv("USERNAME");
    FILE *fileConfig = NULL;
    if(nomUser != NULL)
    {
        string nomFileConf = "ressources/save/";
        nomFileConf += nomUser;
        nomFileConf += "ConfigTouche.dat";

        //on va essayer de lire un premiere foi les fichier de configuration si on y arrive pas alors on le crer
        fileConfig = fopen(nomFileConf.c_str(),"r");
    }
    if(fileConfig == NULL) //si il n'existe pas on le crer et on met des donnee
    {
        fileConfig = fopen("ressources/save/configTouche.dat","w+");

        if(fileConfig != NULL)
        {
            Touche t1 ;
            t1.label = "z";
            t1.valueSDL = SDLK_z;
            Touche t2 ;
            t2.label = "a";
            t2.valueSDL = SDLK_a;
            Touche t3 ;
            t3.label = "DROITE";
            t3.valueSDL = SDLK_RIGHT;
            Touche t4 ;
            t4.label = "GAUCHE";
            t4.valueSDL = SDLK_LEFT;

            GestionTouche::sauverTouche(fileConfig,t3);
            GestionTouche::sauverTouche(fileConfig,t4);
            GestionTouche::sauverTouche(fileConfig,t1);
            GestionTouche::sauverTouche(fileConfig,t2);

            fclose(fileConfig);
        }
        else
            cout << "erreur impossible de crer le fichier de configuaration des touches" << endl;
    }
}

int main(int argc , char ** argv)
{
    crerConfigFile();

    SDL_Surface *ecran = NULL;
    SDL_Init(SDL_INIT_VIDEO);
    TTF_Init();
    SDL_WM_SetCaption("doodle jump", NULL);

    ecran =  SDL_SetVideoMode(800 ,600  , 32, SDL_HWSURFACE | SDL_DOUBLEBUF /*| SDL_NOFRAME | SDL_FULLSCREEN*/);

    string nomFileScoreNouv = "ressources/save/nouveau.dat";

    ListeChainee* listeMoyen = listeScoreMoyenneChaine(nomFileScoreNouv.c_str());
    FenMenu *menu = new FenMenu(ecran);
    FenetreJeu *fen = new FenetreJeu(ecran,listeMoyen, SEUL);
    FenOption *fenOp = new FenOption(ecran);
    FenScores *fenScore = new FenScores(ecran,listeMoyen);
    FenJeuResaux *fenMulti = new FenJeuResaux(ecran);
    Score_struct score ;
    int res = menu->afficher(listeMoyen);

    if(res == DEUXJ)
    {
        fen->setMode(DEUXJOUEUR);
    }

    while(res != QUITTER)
    {
        bool rejouer = false;

        if(res == JOUER || res == DEUXJ)
        {
            fen->initialiser();

            score = fen->lancer(&rejouer);

            // l = listeScore(nomFileScore.c_str()) ;
            if(score.val != -1 && !estVide(score.nom.c_str())) //on efface le fichier et on reecri
            {
                //on va rajouter un score
                //si le score est deja dans le fichier alors on le met a jour si non on le rajoute a la fin du fichier
                FILE *f = fopen(nomFileScoreNouv.c_str(),"r+b");
                if(f != NULL)
                {
                    //on va lire tout les score
                    int posAct = fseek(f,0,SEEK_SET);
                    Score_struct_Moyenne s;
                    do
                    {
                        posAct = ftell(f);
                        s = lireScoreMoyenne(f);
                    }while(!feof(f) && !estVide(s.nom.c_str()) && s.nom != score.nom);

                    Score_struct_Moyenne save;
                    if(estVide(s.nom.c_str()) || s.nom != score.nom ){//on se place a la fin pour ecirre
                        fseek(f,0,SEEK_END);
                        save.nom = score.nom;
                        save.valMax = save.valMin = save.valMoy = score.val;
                        save.nbPartie = 1;
                    }
                    else{ //si on a trouver le bon nom alors on ecrase et on reecrit
                        fseek(f,posAct , SEEK_SET);
                        save.nom = score.nom;
                        save.valMax = (score.val > s.valMax) ? score.val : s.valMax;
                        save.valMin = (score.val < s.valMin) ? score.val : s.valMin;
                        save.nbPartie = s.nbPartie+1;
                        save.valMoy = (s.valMoy*s.nbPartie + score.val)/(save.nbPartie);
                    }
                    cout << "on save le score : " << save.nom << endl;
                    saveScoreMoyenne(save,f);

                    fclose(f);

                }
            }

            delete listeMoyen;
            listeMoyen = listeScoreMoyenneChaine(nomFileScoreNouv.c_str());
            fen->setScores(listeMoyen);
        }
        else if(res == OPTION)
        {
            //si on est re en mode option
            fenOp->afficher();
        }
        else if(res == SCORES)
        {
            fenScore->setScores(listeMoyen);
            fenScore->afficher();
        }else if(res == MULTIJOUEUR)
            fenMulti->afficher();

        if(!rejouer )
        {
            res = menu->afficher(listeMoyen);

            if(res == DEUXJ)
            {
                fen->setMode(DEUXJOUEUR);
            }
            else
                fen->setMode(SEUL);
        }
    }


    SDL_Quit();
    TTF_Quit();

    return 0;
}


